package com.ruoyi.web.Server.BT;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dampcake.bencode.Bencode;
import com.dampcake.bencode.Type;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.web.Server.sys.UserCredentialService;
import com.ruoyi.web.Tool.BT.IPUtils;
import com.ruoyi.web.Tool.BT.TorrentUtils;
import com.ruoyi.web.controller.common.CommonResultStatus;
import com.ruoyi.web.controller.common.base.I18nMessage;
import com.ruoyi.web.controller.common.exception.RocketPTException;
import com.ruoyi.web.dao.BT.TorrentDao;
import com.ruoyi.web.domain.BT.*;
import com.ruoyi.web.Server.sys.UserService;
import com.ruoyi.web.domain.BT.dto.TorrentSearchRequest;
import com.ruoyi.web.domain.BT.dto.TorrentSearchResult;
import com.ruoyi.web.domain.sys.UserCredentialEntity;
import com.ruoyi.web.domain.sys.UserEntity;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.hutool.core.util.RandomUtil;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
@RequiredArgsConstructor
public class TorrentService extends ServiceImpl<TorrentDao, TorrentEntity> {

    final TorrentManager torrentManager;
    final TorrentDao torrentDao;
    final TrackerURLService trackerURLService;
    private final UserCredentialService userCredentialService;
    private final PasskeyManager passkeyManager;

    final UserService userService;
    final TorrentStorageService torrentStorageService;
    final Bencode infoBencode = new Bencode(StandardCharsets.ISO_8859_1);

    public void incrementLeechers(Integer id) {
        // 使用乐观锁或数据库锁确保线程安全
        // 示例使用数据库 update 语句原子性增加
        int rows = torrentDao.incrementLeechers(id);
        if (rows == 0) {
            throw new RocketPTException(CommonResultStatus.FAIL, "Failed to update leechers count");
        }
    }

    public Integer add(TorrentAddParam param) {
        TorrentEntity entity = BeanUtil.copyProperties(param, TorrentEntity.class);
        entity.setStatus(TorrentEntity.Status.CANDIDATE);
        entity.setFileStatus(0);
        entity.setOwner(userService.getUserId());
        entity.setId(torrentDao.countId()+1);
        torrentDao.insert(entity);
        return entity.getId();
    }

    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public void upload(Integer id, byte[] bytes, String filename) {
        System.out.println(bytes);
        TorrentEntity entity = getById(id);
        if (entity == null) {
            throw new RocketPTException(CommonResultStatus.PARAM_ERROR, "该种子不存在");
        }
        if (entity.getFileStatus() == 1) {
            throw new RocketPTException(CommonResultStatus.PARAM_ERROR, "该种子已上传过，如需重传，请删除后再试");
        }
        if (!entity.getOwner().equals(userService.getUserId())) {
            throw new RocketPTException(CommonResultStatus.PARAM_ERROR, "该种子不属于你");
        }


        byte[] transformedBytes = torrentManager.transform(bytes);
        byte[] infoHash = torrentManager.infoHash(bytes);
        System.out.println(infoHash);

        long count = count(Wrappers.<TorrentEntity>lambdaQuery()
                .eq(TorrentEntity::getInfoHash, infoHash));

        if (count != 0) {
            throw new RocketPTException(CommonResultStatus.PARAM_ERROR, "该种子站内已存在。");
        }
        TorrentDto dto = torrentManager.parse(bytes);

        entity.setInfoHash(infoHash);
        entity.setFilename(filename);
        entity.setCreateTime(LocalDateTime.now());
        entity.setUpdateTime(LocalDateTime.now());
        entity.setSize(dto.getTorrentSize());
        entity.setFileCount(dto.getTorrentCount().intValue());
        entity.setType(dto.getTorrentCount() > 1 ? 2 : 1);
        updateById(entity);
        torrentStorageService.save(id, transformedBytes);

    }

    public int getTorrentIdByHash(byte[] infoHash){
        return torrentDao.getTorrentIdByHash(infoHash);
    }


    public byte[] fetch(Integer torrentId, String passkey) {
        byte[] fileBytes = torrentStorageService.read(torrentId);

        if (fileBytes == null) {
            throw new RocketPTException(CommonResultStatus.PARAM_ERROR, I18nMessage.getMessage(
                    "torrent_not_exists"));
        }

        Map<String, Object> decodedMap = infoBencode.decode(fileBytes, Type.DICTIONARY);
        if (StringUtils.isEmpty(passkey)) {
            passkey = userService.getPasskey(userService.getUserId());
        }

        decodedMap.put("announce", trackerURLService.getAnnounce(passkey) + "&torrentId=" + torrentId);

        return infoBencode.encode(decodedMap);
    }


    public Page<TorrentSearchResult> searchTorrents(TorrentSearchRequest request) {
        // 创建分页对象
        Page<TorrentEntity> page = new Page<>(request.getPageNum(), request.getPageSize());

        // 构建查询条件
        QueryWrapper<TorrentEntity> queryWrapper = buildQueryWrapper(request);

        // 执行查询
        Page<TorrentEntity> torrentPage = torrentDao.selectPage(page, queryWrapper);

        // 转换结果
        Page<TorrentSearchResult> resultPage = new Page<>(
                torrentPage.getCurrent(),
                torrentPage.getSize(),
                torrentPage.getTotal()
        );

        for (TorrentEntity torrent : torrentPage.getRecords()) {
            TorrentSearchResult result = new TorrentSearchResult();
            result.setTorrent(torrent);

            // 查询并设置用户信息
            UserEntity owner = getOwnerInfo(torrent.getOwner());
            result.setOwnerInfo(owner);

            resultPage.getRecords().add(result);
        }

        return resultPage;
    }

    private QueryWrapper<TorrentEntity> buildQueryWrapper(TorrentSearchRequest request) {
        QueryWrapper<TorrentEntity> wrapper = new QueryWrapper<>();

        // 精准搜索条件
        if (request.getInfoHash() != null && !request.getInfoHash().isEmpty()) {
            wrapper.eq("info_hash", request.getInfoHash());
        }
        if (request.getCategory() != null) {
            wrapper.eq("category", request.getCategory());
        }
        if (request.getStatus() != null) {
            wrapper.eq("status", request.getStatus());
        }
        if (request.getFileStatus() != null) {
            wrapper.eq("file_status", request.getFileStatus());
        }
        if (request.getOwner() != null) {
            wrapper.eq("owner", request.getOwner());
        }
        if (request.getType() != null) {
            wrapper.eq("type", request.getType());
        }

        // 模糊搜索条件
        if (request.getNameKeyword() != null && !request.getNameKeyword().isEmpty()) {
            wrapper.like("name", request.getNameKeyword());
        }
        if (request.getTitleKeyword() != null && !request.getTitleKeyword().isEmpty()) {
            wrapper.like("title", request.getTitleKeyword());
        }
        if (request.getDescriptionKeyword() != null && !request.getDescriptionKeyword().isEmpty()) {
            wrapper.like("description", request.getDescriptionKeyword());
        }

        // 范围搜索条件
        if (request.getMinSize() != null) {
            wrapper.ge("size", request.getMinSize());
        }
        if (request.getMaxSize() != null) {
            wrapper.le("size", request.getMaxSize());
        }
        if (request.getCreateTimeStart() != null) {
            wrapper.ge("create_time", request.getCreateTimeStart());
        }
        if (request.getCreateTimeEnd() != null) {
            wrapper.le("create_time", request.getCreateTimeEnd());
        }

        // 排序条件
        if (request.getSortField() != null && !request.getSortField().isEmpty()) {
            boolean isAsc = "asc".equalsIgnoreCase(request.getSortDirection());
            wrapper.orderBy(true, isAsc, request.getSortField());
        }

        return wrapper;
    }

    private UserEntity getOwnerInfo(Integer ownerId) {
        return userService.getUserById(ownerId);
    }

    public void audit(TorrentAuditParam param) {


        Integer id = param.getId();
        TorrentEntity entity = getById(id);
        if (entity == null) {
            throw new RocketPTException(CommonResultStatus.PARAM_ERROR, "该种子不存在");
        }
        if (entity.getStatus() != 0) {
            throw new RocketPTException(CommonResultStatus.PARAM_ERROR, "该种子不是待审核状态");
        }
        entity.setReviewer(userService.getUserId());

        entity.setStatus(param.getStatus());
        if (StringUtils.isNotEmpty(param.getRemark())) {
            entity.setRemark(param.getRemark());
        }
        updateById(entity);

    }

    public void update(TorrentEntity entity) {
        Integer id = entity.getId();
        TorrentEntity torrent = getById(id);

        if (torrent == null) {
            throw new RocketPTException(CommonResultStatus.PARAM_ERROR, I18nMessage.getMessage(
                    "torrent_not_exists"));
        }
        if (!entity.getOwner().equals(userService.getUserId())) {
            throw new RocketPTException(CommonResultStatus.PARAM_ERROR, "该种子不属于你");
        }

        torrent.setDescription(entity.getDescription());
        torrent.setTitle(entity.getTitle());
        torrent.setName(entity.getName());
        torrent.setSubheading(entity.getSubheading());
        torrent.setStatus(TorrentEntity.Status.RETRIAL);

        updateById(torrent);
    }

    public void remove(Integer[] ids) {
        for (Integer id : ids) {
            TorrentEntity entity = getById(id);
            if (!entity.getOwner().equals(userService.getUserId())) {
                throw new RocketPTException(CommonResultStatus.PARAM_ERROR, "该种子不属于你");
            }
        }

        removeByIds(Arrays.asList(ids));
    }

    public TorrentEntity getByInfoHash(byte[] infoHash) {
        TorrentEntity entity = getOne(new QueryWrapper<TorrentEntity>()
                        .lambda()
                        .eq(TorrentEntity::getInfoHash, infoHash)
                , false
        );
        return entity;
    }

    /**
     * 收藏或者取消收藏
     */
    public void favorite(Integer torrentId, Integer userId) {

    }


    /**
     * 将普通文件转换为种子文件
     * @param fileBytes       原始文件字节数据
     * @param originalName    原始文件名（不含扩展名）
     * @param announceUrl     tracker地址
     * @return 种子文件字节数据
     */
    public byte[] createTorrentFromFile(byte[] fileBytes, String originalName, String announceUrl)
            throws IOException, RocketPTException {

        try {
            // 生成种子文件名（强制添加.torrent后缀）
            String torrentName = originalName + ".torrent";

            // 创建临时文件
            Path tempFile = Files.createTempFile("upload-", ".tmp");
            Files.write(tempFile, fileBytes);

            // 调用工具类生成种子
            File torrentFile = new File(tempFile.toUri());
            TorrentUtils.createTorrent(
                    torrentFile,
                    new File(tempFile.toUri()),
                    announceUrl
            );

            // 读取生成的种子文件
            byte[] torrentBytes = Files.readAllBytes(tempFile);

            // 清理临时文件
            Files.deleteIfExists(tempFile);

            return torrentBytes;

        } catch (IOException e) {
            log.error("生成种子文件失败: {}", e.getMessage(), e);
            throw new RocketPTException("文件转换失败，请重试");
        }
    }

    /**
     * The purpose of the method:
     * 给当前用户创建passkey凭证信息
     */
     public void createCredential(int userId){

         if (userCredentialService.getById(userId) == null){
             UserEntity userEntity = userService.getUserById(userId);
             UserCredentialEntity userCredentialEntity = new UserCredentialEntity();
             userCredentialEntity.setUserid(userEntity.getUserId().intValue());
             userCredentialEntity.setUsername(userEntity.getUserName());
             userCredentialEntity.setRegIp(IPUtils.getIpAddr());
             userCredentialEntity.setRegType(userEntity.getRegType());
             String checkCode = passkeyManager.generate(userEntity.getUserId().intValue());
             userCredentialEntity.setCheckCode(checkCode);

             // 生成随机盐和密码
             String salt = RandomUtil.randomString(8);
             String passkey = passkeyManager.generate(userEntity.getUserId().intValue());

             userCredentialEntity.setSalt(salt);
             userCredentialEntity.setPasskey(passkey);
             String generatedPassword = userCredentialService.generate(userEntity.getPassword(), salt);
             userCredentialEntity.setPassword(generatedPassword);
             // 保存用户凭证实体
             userCredentialService.save(userCredentialEntity);
         }

     }


    public List<TorrentEntity> advancedSearch(AdvancedTorrentParam param){
         return torrentDao.advancedSearch(param);
    }
}

